package util

import (
	"bytes"
	"dag2.0/gat1400-proxy/logger"
	"encoding/json"
	"errors"
	jsoniter "github.com/json-iterator/go"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

var workerHttpClient = &http.Client{
	Transport: &http.Transport{
		MaxIdleConns:        20,
		MaxIdleConnsPerHost: 5,
		MaxConnsPerHost:     5,
		IdleConnTimeout:     5 * time.Minute,
	},
	Timeout: 5 * time.Minute, //粗粒度 时间计算包括从连接(Dial)到读完response body
	CheckRedirect: func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}, //禁止重定向
}

// http请求
func Request(url, method string, headMap map[string]string, body interface{}, resPointer interface{}) ([]byte, http.Header, int, error) {
	if !strings.HasPrefix(url, "http://") {
		url = `http://` + url
	}
	var bodyBytes []byte
	var resBytes []byte
	var header http.Header
	var code int
	if body != nil {
		//bodyBytes, _ = jsoniter.Marshal(body)
		bodyBytes, _ = json.Marshal(body)
		logger.LOG_INFO("======bodyBytes: ", BytesString(bodyBytes))
	}
	err := Retry(func() error {
		req, err := http.NewRequest(method, url, bytes.NewReader(bodyBytes))
		if err != nil {
			return err
		}
		if headMap != nil {
			for key, value := range headMap {
				req.Header.Set(key, value)
			}
		}
		res, err := workerHttpClient.Do(req)
		if err != nil {
			return err
		}
		defer func() {
			err := res.Body.Close()
			if err != nil {
				logger.LOG_WARN("关闭res失败", err)
			}
		}()
		resBytes, err = ioutil.ReadAll(res.Body)
		header = res.Header
		code = res.StatusCode
		if err != nil {
			return err
		}
		//_ = res.Body.Close()
		//if !(res.StatusCode == http.StatusOK || res.StatusCode == http.StatusUnauthorized ||
		//	res.StatusCode == http.StatusCreated||res.StatusCode == http.StatusNoContent){
		//	return errors.New(string(resBytes))
		//}
		return nil
	}, 3, 3*time.Second)
	if err != nil {
		return resBytes, header, code, err
	}
	if resPointer != nil {
		res := &ResponseWrap{}
		logger.LOG_DEBUG("response:", string(resBytes))
		err = jsoniter.Unmarshal(resBytes, res)
		if err != nil {
			return nil, header, code, err
		}
		if res.Code != http.StatusOK {
			return nil, header, code, errors.New("error response code:" + strconv.Itoa(res.Code))
		}
		if res.Data != nil && len(res.Data) > 0 {
			return nil, header, code, jsoniter.Unmarshal(res.Data, resPointer)
		}
	}
	return resBytes, header, code, nil
}

func RequestVIID(url, method string, headMap map[string]string, bodyBytes []byte, resPointer interface{}) ([]byte, http.Header, int, error) {
	if !strings.HasPrefix(url, "http://") {
		url = `http://` + url
	}
	var resBytes []byte
	var header http.Header
	var code int
	//if body != nil {
	//	//bodyBytes, _ = jsoniter.Marshal(body)
	//	bodyBytes, _ = json.Marshal(body)
	//	logger.LOG_INFO("======bodyBytes: ", BytesString(bodyBytes))
	//}
	err := Retry(func() error {
		req, err := http.NewRequest(method, url, bytes.NewReader(bodyBytes))
		if err != nil {
			return err
		}
		if headMap != nil {
			for key, value := range headMap {
				req.Header.Set(key, value)
			}
		}
		res, err := workerHttpClient.Do(req)
		if err != nil {
			return err
		}
		defer func() {
			err := res.Body.Close()
			if err != nil {
				logger.LOG_WARN("关闭res失败", err)
			}
		}()
		resBytes, err = ioutil.ReadAll(res.Body)
		header = res.Header
		code = res.StatusCode
		if err != nil {
			return err
		}
		//_ = res.Body.Close()
		//if !(res.StatusCode == http.StatusOK || res.StatusCode == http.StatusUnauthorized ||
		//	res.StatusCode == http.StatusCreated||res.StatusCode == http.StatusNoContent){
		//	return errors.New(string(resBytes))
		//}
		return nil
	}, 3, 3*time.Second)
	if err != nil {
		return resBytes, header, code, err
	}
	if resPointer != nil {
		res := &ResponseWrap{}
		logger.LOG_DEBUG("response:", string(resBytes))
		err = jsoniter.Unmarshal(resBytes, res)
		if err != nil {
			return nil, header, code, err
		}
		if res.Code != http.StatusOK {
			return nil, header, code, errors.New("error response code:" + strconv.Itoa(res.Code))
		}
		if res.Data != nil && len(res.Data) > 0 {
			return nil, header, code, jsoniter.Unmarshal(res.Data, resPointer)
		}
	}
	return resBytes, header, code, nil
}

type ResponseWrap struct {
	Code    int                 `json:"code"`
	Data    jsoniter.RawMessage `json:"data"`
	Success bool                `json:"success"`
	Message string              `json:"message"`
}
